package coreMonitor

import (
	"context"
	"runtime"
	"sync"
	"time"

	"gitee.com/xgh2012/api-core/coreZapLog"
	"go.uber.org/zap"
)

// PerformanceMonitor 性能监控器
type PerformanceMonitor struct {
	mu       sync.RWMutex
	metrics  map[string]*Metric
	enabled  bool
	interval time.Duration
	stopCh   chan struct{}
}

// Metric 性能指标
type Metric struct {
	Name      string        `json:"name"`
	Count     int64         `json:"count"`
	TotalTime time.Duration `json:"total_time"`
	AvgTime   time.Duration `json:"avg_time"`
	MaxTime   time.Duration `json:"max_time"`
	MinTime   time.Duration `json:"min_time"`
	LastTime  time.Time     `json:"last_time"`
}

// NewPerformanceMonitor 创建性能监控器
func NewPerformanceMonitor(interval time.Duration) *PerformanceMonitor {
	return &PerformanceMonitor{
		metrics:  make(map[string]*Metric),
		enabled:  true,
		interval: interval,
		stopCh:   make(chan struct{}),
	}
}

// Start 启动监控
func (pm *PerformanceMonitor) Start() {
	if !pm.enabled {
		return
	}

	go func() {
		ticker := time.NewTicker(pm.interval)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				pm.logSystemMetrics()
			case <-pm.stopCh:
				return
			}
		}
	}()
}

// Stop 停止监控
func (pm *PerformanceMonitor) Stop() {
	close(pm.stopCh)
}

// RecordDuration 记录执行时间
func (pm *PerformanceMonitor) RecordDuration(name string, duration time.Duration) {
	if !pm.enabled {
		return
	}

	pm.mu.Lock()
	defer pm.mu.Unlock()

	metric, exists := pm.metrics[name]
	if !exists {
		metric = &Metric{
			Name:     name,
			MinTime:  duration,
			MaxTime:  duration,
			LastTime: time.Now(),
		}
		pm.metrics[name] = metric
	}

	metric.Count++
	metric.TotalTime += duration
	metric.AvgTime = metric.TotalTime / time.Duration(metric.Count)
	metric.LastTime = time.Now()

	if duration > metric.MaxTime {
		metric.MaxTime = duration
	}
	if duration < metric.MinTime {
		metric.MinTime = duration
	}
}

// GetMetrics 获取所有指标
func (pm *PerformanceMonitor) GetMetrics() map[string]*Metric {
	pm.mu.RLock()
	defer pm.mu.RUnlock()

	result := make(map[string]*Metric)
	for k, v := range pm.metrics {
		result[k] = &Metric{
			Name:      v.Name,
			Count:     v.Count,
			TotalTime: v.TotalTime,
			AvgTime:   v.AvgTime,
			MaxTime:   v.MaxTime,
			MinTime:   v.MinTime,
			LastTime:  v.LastTime,
		}
	}
	return result
}

// logSystemMetrics 记录系统指标
func (pm *PerformanceMonitor) logSystemMetrics() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	coreZapLog.Logger.Info("系统性能指标",
		zap.Uint64("alloc_mb", bToMb(m.Alloc)),
		zap.Uint64("total_alloc_mb", bToMb(m.TotalAlloc)),
		zap.Uint64("sys_mb", bToMb(m.Sys)),
		zap.Uint32("num_gc", m.NumGC),
		zap.Int("num_goroutine", runtime.NumGoroutine()),
	)
}

// bToMb 字节转MB
func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}

// TimerFunc 计时器函数装饰器
func (pm *PerformanceMonitor) TimerFunc(name string, fn func() error) error {
	start := time.Now()
	defer func() {
		pm.RecordDuration(name, time.Since(start))
	}()
	return fn()
}

// TimerFuncWithContext 带上下文的计时器函数装饰器
func (pm *PerformanceMonitor) TimerFuncWithContext(ctx context.Context, name string, fn func(context.Context) error) error {
	start := time.Now()
	defer func() {
		pm.RecordDuration(name, time.Since(start))
	}()
	return fn(ctx)
}

// GlobalMonitor 全局性能监控器实例
var GlobalMonitor = NewPerformanceMonitor(30 * time.Second)

// RecordDuration 便捷函数
func RecordDuration(name string, duration time.Duration) {
	GlobalMonitor.RecordDuration(name, duration)
}

func TimerFunc(name string, fn func() error) error {
	return GlobalMonitor.TimerFunc(name, fn)
}

func TimerFuncWithContext(ctx context.Context, name string, fn func(context.Context) error) error {
	return GlobalMonitor.TimerFuncWithContext(ctx, name, fn)
}

func GetMetrics() map[string]*Metric {
	return GlobalMonitor.GetMetrics()
}

func StartMonitor() {
	GlobalMonitor.Start()
}

func StopMonitor() {
	GlobalMonitor.Stop()
}
